if endpoint in getattr(app, 'view_functions', {}): previous_view_class = app.view_functions[endpoint].__dict__['view_class'] if previous_view_class != resource: raise ValueError('This endpoint (%s) is already set to the class %s.' % (endpoint, previous_view_class.__name__)) # 获取 mediatypes resource.mediatypes = self.mediatypes_method() # Hacky resource.endpoint = endpoint # 这里很重要 # 路由对应的类 resource 继承的是 Resource,Resource 继承自 MethodView 并且重写了 dispatch_request,MethodView 的元类是 MethodViewType 和 View。所以,resource.as_view 调用的是 View 中的 as_view 方法,as_view 方法的返回是一个函数,只不过函数中存在路由对应的类的属性。 # self.output 的参数是 resource.as_view 的返回值。 resource_func = self.output(resource.as_view(endpoint, *resource_class_args, **resource_class_kwargs))
for decorator in self.decorators: resource_func = decorator(resource_func)
for url in urls: # If this Api has a blueprint if self.blueprint: # And this Api has been setup if self.blueprint_setup: # Set the rule to a string directly, as the blueprint is already # set up. self.blueprint_setup.add_url_rule(url, view_func=resource_func, **kwargs) continue else: # Set the rule to a function that expects the blueprint prefix # to construct the final url. Allows deferment of url finalization # in the case that the associated Blueprint has not yet been # registered to an application, so we can wait for the registration # prefix rule = partial(self._complete_url, url) else: # If we've got no Blueprint, just build a url with no prefix rule = self._complete_url(url, '') # 最后还是调用 flask 的 add_url_rule 方法将路由和函数进行关联映射 app.add_url_rule(rule, view_func=resource_func, **kwargs)